// 可移动物品类
class Moveable extends Subscriber{
  constructor({name, type, x, y, width, height, game, hp, speed}) {
    super();
    this.name = name;
    this.hits = hp;
    this.hits_max = hp;
    this.rotateDeg = undefined;
    if(!Object.values(MOB_TYPES).includes(type)){
      throw Error('moveable type error!')
    }
    this.type = type;
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
    this.game = game;
    // 投射物，也是属于Moveable类,可以是子弹，火球等等，这样的结构，子母弹实现也很容易
    this.projectiles = [];
    // 当前运动趋势，角度
    this.angle = undefined;
    this.speed = speed;
  }
  // 获取该对象的css属性，仅供vue render使用
  get cssObject(){
    return {
      left:`${(this.x)}px`,
      top: `${(this.y)}px`,
      width: `${this.width}px`,
      height: `${this.height}px`
    }
  }
  // 弧度
  get radian() {
    return this.angle * Math.PI/180;
  }
  // 通过弧度设置角度
  set radian(radian) {
    this.angle = radian * 180 / Math.PI
  }
  // 获取该对象的矩形4个顶点的信息
  get rect() {
    return getRectByPosition(this.x, this.y, this.width, this.height);
  }
  isPointOutRect({x, y}, rect) {
    return x <= rect.leftTop.x || 
           x >= rect.rightTop.x ||
           y <= rect.leftTop.y || 
           y >= rect.leftBottom.y
  }
  collisionDetection(rect) {
    // 碰撞检测，返回true代表检测通过，否则不通过，为了简化逻辑都当作矩形处理
    return Object.values(rect).every(p => this.isPointOutRect(p, this.rect)) && 
           Object.values(this.rect).every(p => this.isPointOutRect(p, rect))
  }
  preMove(range, allowOutSide = false) {
    // allowOutSide 是否允许超出画面范围（一般来讲玩家不允许而怪物和子弹允许）
    // 计算出下一步将移动到的位置(仅计算，并不移动)
    let targetX = Math.cos(this.radian) * range + this.x
    let targetY = Math.sin(this.radian) * range + this.y
    let isOutSideX = false, isOutSideY = false;
    if(this.game){
      const {mapWidth, mapHeight} = this.game
      const {height, width} = this
      if(allowOutSide) {
        isOutSideX = this.x < - width || this.x > mapWidth
        isOutSideY = this.y < - height || this.y > mapHeight
        targetX = isOutSideX ? this.x : targetX
        targetY = isOutSideY ? this.y : targetY
      }else {
        if(targetX < 0) {
          targetX = 0
        }
        if(targetX > mapWidth - width) {
          targetX = mapWidth - width
        }
        if(targetY < 0) {
          targetY = 0
        }
        if(targetY > mapHeight - height) {
          targetY = mapHeight - height
        }
      }
    }
    return {
      x: targetX,
      y: targetY,
      isOutSide: isOutSideX && isOutSideY // 是否完全在画面外
    }
  }
  get hp() {
    return this.hits;
  }
  set hp(hp) {
    if(hp < 0) {
      hp = 0;
    }
    this.hits = hp;
    if(!this.hp) {
      this.release();
    }
  }
  move(x, y) {
    this.x = x;
    this.y = y;
    this.emit('move', {x, y})
  }
  removeProjectile(projectile) {
    let pos = this.projectiles.indexOf(projectile);
    if(pos>=0) {
      this.projectiles.splice(pos, 1)
    }
  }
  release() {
    this.game = null;
  }
}

